(function(angular) {
	'use strict';
	angular.module('fs.waf').factory('feeCodeService', feeCodeService);
	feeCodeService.$inject = [ '$q', 'loggerFactory', 'ajaxServiceFactory', 'gridService', 'modalService', 'formatService', 'arithService', '$timeout', 'commonService', 'Constants'];
	function feeCodeService($q, loggerFactory, ajaxServiceFactory, gridService, modalService, formatService, arithService, $timeout, commonService, Constants) {
		var ajaxService = ajaxServiceFactory.buildAjaxService({
			getFeeCodeOptions : {
				url : 'do/cda/dataList/feeCodeSetupOptions',
				method : 'get'
			},
			getFeeCalcTypeOptions : {
				url : 'do/cda/dataList/getFeeCalcTypeOptions',
				method : 'get'
			},
			getFeeCodeLayout : {
				url : 'do/cda/feeCode/layout',
				method : 'post'
			}
		});	
		
		function initOptionData(ctrl, $scope, viewFlag) {
			var defer = $q.defer();
			getFeeCodeOptions().then(function(response) {
				ctrl.feeTypeOptions = response.feeTypeOptions;
				ctrl.feeCcyOptions = response.currencyOptions;
				ctrl.feeLimitCcyOptions = response.currencyOptions;
				ctrl.amortizeMinCcyOptions = response.currencyOptions;
				ctrl.tierCcyOptions = response.currencyOptions;
				ctrl.feeCalcTypeOptions = response.feeCalcTypeOptions;	
				ctrl.allFeeCalcBasisOptions = response.feeCalcBasisOptions;	
				ctrl.plusBaseRateFlagOptions = response.yesNoOptions;
				ctrl.allAmortizeFlagOptions = angular.copy(response.yesNoOptions);
				ctrl.amortizeFlagOptions = angular.copy(response.yesNoOptions);
				ctrl.amortEarlyFlagOptions = response.yesNoOptions;
				ctrl.tierCalcTypeOptions = response.tierCalcTypeOptions;
				ctrl.allocCodeOptions = response.allocCodeOptions;
				ctrl.tierByOptions = angular.copy(response.tierByOptions);
				ctrl.copyTierTypeOptions = angular.copy(ctrl.tierByOptions);
				ctrl.tierBy2Options = angular.copy(response.tierByOptions);
				ctrl.copyTierType2Options = angular.copy(ctrl.tierBy2Options);
				ctrl.visibilityTypeOptions = response.visibilityTypeOptions;
				defer.resolve();
			}, angular.noop);
			
			ctrl.feeCalcBasisChanged = function(value) {
				if (ctrl.feeCode.calcBase) {
					controlTierCalcType(ctrl);
				}
			};
			
			ctrl.feeCalcTypeChanged = function(value) {
				if (ctrl.feeCode.feeCalcType) {
					// feeCalcBasis
					var feeCalcBasisData = [];
					for (var i = 0; i < ctrl.allFeeCalcBasisOptions.length; i++) {
						var _feeCalcBase = ctrl.allFeeCalcBasisOptions[i];
						var _filterTypes = _feeCalcBase.feeCalcType;
						if (_filterTypes && _filterTypes.indexOf(ctrl.feeCode.feeCalcType) >= 0) {
							feeCalcBasisData.push(_feeCalcBase);
						}
					}
					ctrl.feeCalcBasisOptions = feeCalcBasisData;
					//default value.
					if(ctrl.feeCode.feeCalcType != 'U') {
						if(!ctrl.feeCode.calcBase || !commonService.isValidOption(ctrl.feeCalcBasisOptions, ctrl.feeCode.calcBase)) {
							ctrl.feeCode.calcBase = "A";
						}
					}
					if (ctrl.feeCode.feeCalcType != 'I') {
//						ctrl.feeCode.plusBaseRateFlag = ctrl.feeCode.plusBaseRateFlag || 'N';
						ctrl.feeCode.plusBaseRateFlag = 'N';
					}
					if (!(ctrl.feeCode.feeCalcType == 'P' || ctrl.feeCode.feeCalcType == 'I' || ctrl.feeCode.feeCalcType == 'U')) {
						delete ctrl.feeCode.feeLimitCcy;
						delete ctrl.feeCode.feeLimitMin;
						delete ctrl.feeCode.feeLimitMax;
					}
					if (!(ctrl.feeCode.feeCalcType == 'F' || ctrl.feeCode.feeCalcType == 'U')) {
						delete ctrl.feeCode.feeCcy;
					}
					
					if (!(ctrl.feeCode.feeCalcType == 'F' || ctrl.feeCode.feeCalcType == 'P' || ctrl.feeCode.feeCalcType == 'U')) {
						ctrl.feeCode.amortizeFlag = 'N';
					}
					
					controlTierCalcType(ctrl);
					
					changeColumnDefsForTierType(ctrl, $scope, viewFlag);
				}
			};
			
			ctrl.feeCcyChanged = function(value) {
			};
			
			ctrl.feeTypeChanged = function(model) {
				if (ctrl.feeCode.feeType) {
					// calc fee code
					calcFeeCode(ctrl);
					//  It can be Y only when AMORTIZE_FLAG of its fee type (in FEETYPE table) is Y
					var amortizeFlagFromFeeType;
					for (var a = 0; a < ctrl.feeTypeOptions.length; a++) {
						if (ctrl.feeTypeOptions[a].value == ctrl.feeCode.feeType) {
							amortizeFlagFromFeeType = ctrl.feeTypeOptions[a].extProperty.amortizeFlag;
							break;
						}
					}
					if (amortizeFlagFromFeeType == 'Y') {
						// feecode amortizeFlag can be 'Y' and 'N' to choice
						ctrl.amortizeFlagOptions = angular.copy(ctrl.allAmortizeFlagOptions);
					} else {
						// delete "Y"
						for (var i = 0; i < ctrl.amortizeFlagOptions.length; i++) {
							if (ctrl.amortizeFlagOptions[i].value == 'Y') {
								ctrl.amortizeFlagOptions.splice(i, 1);
								break;
							}
						}
						if (ctrl.feeCode.amortizeFlag == 'Y') {
							ctrl.feeCode.amortizeFlag = 'N';
						}
					}
				}
			};
			ctrl.tierByChanged = function(model) {
				console.log(model);
			};
			
			ctrl.feeCodeNameChanged = function(model) {
				if (ctrl.feeCode.feeCodeName) {
					calcFeeCode(ctrl);
				}
			}
			function calcFeeCode(ctrl) {
				if(!ctrl.feeCode.feeCode && ctrl.feeCode.feeType && ctrl.feeCode.feeCodeName) {
					ctrl.feeCode.feeCode = ctrl.feeCode.feeType + '-' + ctrl.feeCode.feeCodeName;
				} else if (ctrl.feeCode.feeType && ctrl.feeCode.feeCodeName && ctrl.feeCode.feeCode.indexOf(Constants.ENCODE_SEPARATOR) == -1) {
					ctrl.feeCode.feeCode = ctrl.feeCode.feeType + '-' + ctrl.feeCode.feeCodeName;
				}
			}
			
			ctrl.amortizeFlagChanged = function(value) {
				if (ctrl.feeCode.amortizeFlag && ctrl.feeCode.amortizeFlag != 'Y') {
					delete ctrl.feeCode.amortizeMinCcy;
					delete ctrl.feeCode.amortizeMinAmount;
					ctrl.feeCode.amortEarlyFlag = 'N';
				}
			};
			
			return defer.promise;
		}
		function getFeeCodeOptions() {
			var defer = $q.defer();
			ajaxService.getFeeCodeOptions().then(function(response) {
				var feeCodeOptions = {};
				if (response.data) {
					angular.forEach(response.data, function(value, key) {
						feeCodeOptions[key] = value;
					});
				}
				defer.resolve(feeCodeOptions);
			});
			return defer.promise;
		}
		
		function initLayoutAndModel($scope, ctrl, initFeeCode, layoutConfig, viewFlag) {
			var defer = $q.defer();
			if(initFeeCode.tierType && initFeeCode.tierType != 'N'){
				initFeeCode.oldTierType = initFeeCode.tierType;
				initFeeCode.oldTierType2 = initFeeCode.tierType2;
				var params = {};
				params.action = initFeeCode.action;
				params.tierType = initFeeCode.tierType;
				if(initFeeCode.tierType2){
					params.tierType2 = initFeeCode.tierType2;
				}
				if(initFeeCode.tierCalcType){
					params.tierCalcType = initFeeCode.tierCalcType;
				}
				ajaxService.getFeeCodeLayout(params).then(function(response) {
					var tmp = angular.copy(initFeeCode);
					ctrl.layoutConfig = response.data;
					// reset model after change layout
					$timeout(function(){
						ctrl.feeCode = tmp;
						changeColumnDefsForTierType(ctrl, $scope, viewFlag);
						defer.resolve();
					});
				});
			} else {
				ctrl.layoutConfig = layoutConfig;
				ctrl.feeCode = initFeeCode;
				changeColumnDefsForTierType(ctrl, $scope, viewFlag);
				defer.resolve();
			}
			return defer.promise;
		}
		
		function initTierCriteria(initLayoutConfig, $scope, ctrl, viewFlag) {
			//init tierCriterias
			if(ctrl.validatorConfig) initLayoutConfig.formConfigs.tierCriteria.tableConfigs.table.validatorConfig = ctrl.validatorConfig.tierCriterias;
			ctrl.tierCriteriaInnerGridOptions = gridService.createInnerGridOptions($scope, initLayoutConfig.formConfigs.tierCriteria.tableConfigs.table, tierCriteriaRowSelectionChanged);
			ctrl.tierCriteriaInnerGridOptions.data = 'vm.feeCode.tierCriterias';
			ctrl.tierCriteriaInnerGridOptions.verifyData  = 'vm.feeCodeOld.tierCriterias';
			// hidden add when subline
			ctrl.tierCriteriaInnerGridOptions.filterRowOperation = function(row, type){
			      if(row && row.entity && row.entity.hasFrontSameCriteria == 'Y' && type == 'add') {
			    	  return true;
			      } else {
			    	  return false;// default show
			      }
		    };
			function tierCriteriaRowSelectionChanged(eventRow, selectedRows) {
				ctrl.selectedTierCriterias = selectedRows;
			}
			
			ctrl.tierTypeChanged = function(value) {
				if (ctrl.feeCode.tierType && ctrl.feeCode.tierType != 'N') {
					// readonly and also need clear data
					ctrl.feeCode.feeValueAmt = 0;
					ctrl.feeCode.feeValuePerc = '';
					ctrl.feeCode.feeValueRate = '';
					
					//remove the tiertype
					var resultOptions = [];
					angular.forEach(ctrl.copyTierType2Options, function(obj) {
						if (obj.value != ctrl.feeCode.tierType) {
							resultOptions.push(obj);
						}
					});
					ctrl.tierBy2Options = resultOptions;
				}
				
				// need clear
				if (ctrl.feeCode.tierType == 'N') {
					ctrl.feeCode.tierCriterias = [];
					ctrl.feeCode.tierType2 = 'N';
					ctrl.feeCode.tierCalcType = 'N';
				}
				
				changeLayoutBySpreadTierType();
				
				controlTierCalcType(ctrl);
			};
			
			ctrl.tierType2Changed = function(value) {
				if (ctrl.feeCode.tierType2 && ctrl.feeCode.tierType2 != 'N') {
					//remove the tiertype
					var resultOptions = [];
					angular.forEach(ctrl.copyTierTypeOptions, function(obj) {
						if (obj.value != ctrl.feeCode.tierType2) {
							resultOptions.push(obj);
						}
					});
					ctrl.tierByOptions = resultOptions;
				}
				
				if (ctrl.feeCode.tierType2) {
					// tierType2 != 'N' need hidden some first column criteria
					// tierType2 == 'N' also need open hidden first column
					resetTierCriteria(ctrl);
				}
				
				changeLayoutBySpreadTierType2();
				
				controlTierCalcType(ctrl);
			};
			
			function changeLayoutBySpreadTierType() {
				if(ctrl.feeCode.tierType && ctrl.feeCode.tierType != ctrl.feeCode.oldTierType){
					ctrl.feeCode.oldTierType = ctrl.feeCode.tierType;
					var params = {};
					params.action = ctrl.feeCode.action;
					params.tierType = ctrl.feeCode.tierType;
					if(ctrl.feeCode.tierType2){
						params.tierType2 = ctrl.feeCode.tierType2;
					}
					if(ctrl.feeCode.tierCalcType){
						params.tierCalcType = ctrl.feeCode.tierCalcType;
					}
					ajaxService.getFeeCodeLayout(params).then(function(response) {
						var tmp = angular.copy(ctrl.feeCode);
						// 1. change layout
						ctrl.layoutConfig = response.data;
						// reset model after change layout
						$timeout(function(){
							changeColumnDefsForTierType(ctrl, $scope, viewFlag);
							ctrl.feeCode = tmp;
						});
					});
				}
			}
			
			function changeLayoutBySpreadTierType2() {
				if(ctrl.feeCode.tierType2 && ctrl.feeCode.tierType2 != ctrl.feeCode.oldTierType2){
					ctrl.feeCode.oldTierType2 = ctrl.feeCode.tierType2;
					var params = {};
					params.action = ctrl.feeCode.action;
					if(ctrl.feeCode.tierType){
						params.tierType = ctrl.feeCode.tierType;
					}
					params.tierType2 = ctrl.feeCode.tierType2;
					if(ctrl.feeCode.tierCalcType){
						params.tierCalcType = ctrl.feeCode.tierCalcType;
					}
					ajaxService.getFeeCodeLayout(params).then(function(response) {
						var tmp = angular.copy(ctrl.feeCode);
						// 1. change layout
						ctrl.layoutConfig = response.data;
						// reset model after change layout
						$timeout(function(){
							changeColumnDefsForTierType(ctrl, $scope, viewFlag);
							ctrl.feeCode = tmp;
						});
					});
				};
			}
			
			ctrl.criteriaChanged = function(currTierCriteria) {
				// if master, then need reset sub line
				angular.forEach(ctrl.feeCode.tierCriterias, function(tierCriteria, index) {
					if (tierCriteria.$$hashKey == currTierCriteria.$$hashKey) {
						if (index < ctrl.feeCode.tierCriterias.length - 1) {
							for (var i = index + 1; i < ctrl.feeCode.tierCriterias.length; i++) {
								var tierCriteria = ctrl.feeCode.tierCriterias[i];
								// belong to master
								if (tierCriteria.hasFrontSameCriteria == 'Y') {
									tierCriteria.criteria = currTierCriteria.criteria;
								} else {
									break;
								}
							}
						}
					}
				});
			};
			
			ctrl.criteria2Changed = function(currTierCriteria) {
			};
			
			ctrl.addTierCriteria = function(newTierCriteria) {
				if (!ctrl.feeCode.tierCriterias) {
					ctrl.feeCode.tierCriterias = [];
				}
				newTierCriteria.hasFrontSameCriteria = 'N';
			};
			
			ctrl.removeTierCriteria = function() {		
				angular.forEach(ctrl.selectedTierCriterias, function(selectedTierCriteria, key) {
					angular.forEach(ctrl.feeCode.tierCriterias, function(tierCriteria, index) {
						if (tierCriteria.$$hashKey == selectedTierCriteria.$$hashKey) {
							// need exclude, will be remove by framework
							tierCriteria.removeSelectedFlag = true;
						}
					});
				});
				// delete need also reset hasFrontSameCriteria, because some first line can be delete
				resetTierCriteria (ctrl);
			};
			
			ctrl.addTier2Criteria = function(currRow) {
				if (ctrl.feeCode.tierType2 == 'N') {
					modalService.openErrorDialogs({
						messages : [ 'Please select a valid Tier Type2 first!' ]
					});
					return;
				}
				var _selectedTierCriteria;
				var _selectedTierCriteriaIndex;
				var selectedNum = 0;
				angular.forEach(ctrl.feeCode.tierCriterias, function(tierCriteria, index) {
					if (tierCriteria.$$hashKey == currRow.entity.$$hashKey) {
						_selectedTierCriteria = tierCriteria;
						_selectedTierCriteriaIndex = index;
						selectedNum = selectedNum + 1;
					}
				});
				var nextMasterRowIndex;
				if (_selectedTierCriteriaIndex + 1 < ctrl.feeCode.tierCriterias.length) {
					for (var i = _selectedTierCriteriaIndex + 1; i < ctrl.feeCode.tierCriterias.length; i++) {
						if (ctrl.feeCode.tierCriterias[i].hasFrontSameCriteria == 'N') {
							nextMasterRowIndex = i;
							break;
						}
					}
				}
				if (!nextMasterRowIndex) nextMasterRowIndex = ctrl.feeCode.tierCriterias.length;
				
				var newTierCriteria = {};
				newTierCriteria.hasFrontSameCriteria = 'Y';
				newTierCriteria.criteria = _selectedTierCriteria.criteria;
				
				ctrl.feeCode.tierCriterias.splice(nextMasterRowIndex, 0, newTierCriteria);
			};
		}
		
		function changeColumnDefsForTierType(ctrl, $scope, viewFlag) {
			if (!ctrl.feeCode) return;
			if (ctrl.feeCode.tierType != ctrl.feeCode.tmpOldTierType 
				|| ctrl.feeCode.tierType2 != ctrl.feeCode.tmpOldTierType2 
				|| ctrl.feeCode.feeCalcType != ctrl.feeCode.tmpOldFeeCalcType ) {
				ctrl.feeCode.tmpOldTierType = ctrl.feeCode.tierType;
				ctrl.feeCode.tmpOldTierType2 = ctrl.feeCode.tierType2;
				ctrl.feeCode.tmpOldFeeCalcType = ctrl.feeCode.feeCalcType;
				// Amount:A U
				// other is number
				var dynamicType, dynamicFormat;
				if (ctrl.feeCode.tierType == 'A') {
					dynamicType = "money";
					dynamicFormat = "vm.feeCode.dynamicParams.TXN_CCY.value";
				} else if (ctrl.feeCode.tierType == 'U') {
					dynamicType = "money";
					dynamicFormat = "vm.feeCode.dynamicParams.ASSET_CCY.value";
				} else if (ctrl.feeCode.tierType == 'C') {
					if (ctrl.feeCode.dynamicParams && ctrl.feeCode.dynamicParams.USE_SCORE && ctrl.feeCode.dynamicParams.USE_SCORE.value && ctrl.feeCode.dynamicParams.USE_SCORE.value == 'N') {
						// TODO only char, need change
						dynamicType = "number";
						dynamicFormat = "integer";
					} else {//default use_scope is 'Y'
						dynamicType = "number";
						dynamicFormat = "integer";
					}
				} else if (ctrl.feeCode.tierType == 'T') {	//TXN TENOR
					dynamicType = "number";
//					dynamicFormat = "integer";
					dynamicFormat = "vm.feeCode.dynamicParams.STATIC_TERM_PERIOD.value";
				} else {
					// default
					dynamicType = "number";
					dynamicFormat = "integer";
				}
				var dynamicType2, dynamicFormat2;
				if (ctrl.feeCode.tierType2 == 'A') {
					dynamicType2 = "money";
					dynamicFormat2 = "vm.feeCode.dynamicParams.TXN_CCY.value";
				} else if (ctrl.feeCode.tierType2 == 'U') {
					dynamicType2 = "money";
					dynamicFormat2 = "vm.feeCode.dynamicParams.ASSET_CCY.value";
				} else if (ctrl.feeCode.tierType2 == 'C') {
					if (ctrl.feeCode.dynamicParams && ctrl.feeCode.dynamicParams.USE_SCORE && ctrl.feeCode.dynamicParams.USE_SCORE.value && ctrl.feeCode.dynamicParams.USE_SCORE.value == 'N') {
						// TODO only char, need change
						dynamicType2 = "number";
						dynamicFormat2 = "integer";
					} else {//default use_scope is 'Y'
						dynamicType2 = "number";
						dynamicFormat2 = "integer";
					}
				} else if (ctrl.feeCode.tierType == 'T') {	//TXN TENOR
					dynamicType2 = "number";
					dynamicFormat2 = "integer";
				} else {
					// default
					dynamicType2 = "number";
					dynamicFormat2 = "integer";
				}
				var dynamicType3, dynamicFormat3;
				if (ctrl.feeCode.feeCalcType == 'I' || ctrl.feeCode.feeCalcType == 'P') {
					dynamicType3 = "percentage";
					dynamicFormat3 = "defaultPercentage";
				} else {
					// default
					dynamicType3 = "money";
					dynamicFormat3 = "vm.feeCode.feeCcy";
				}
				var columnDefs = [
                  {
                	  "label": "label.feecode.criteria",
                	  "model": "criteria",
                	  "type": dynamicType,
                	  "readonly": viewFlag,
                	  "format": dynamicFormat,
                	  "options": {
                		  "callback":{"changed" : "vm.criteriaChanged"}
                	  },
                	  "show": "row.entity.hasFrontSameCriteria == 'N'"
                  },
                  {
                	  "label": "label.feecode.criteriavalue",
                	  "model": "criteriaValue",
                	  "type": dynamicType3,
                	  "readonly": viewFlag,
                	  "format": dynamicFormat3,
                	  "options": {}
                  }
                ];
				var columnDefs2 = [
                   {
                	   "label": "label.feecode.criteria",
                	   "model": "criteria",
                	   "type": dynamicType,
                	   "format": dynamicFormat,
                	   "readonly": viewFlag,
                	   "options": {
                		   "callback":{"changed" : "vm.criteriaChanged"}
                	   },
                	   "show": "row.entity.hasFrontSameCriteria == 'N'"
                   },{
                	   "label": "label.feecode.criteria2",
                	   "model": "criteria2",
                	   "type": dynamicType2,
                	   "format": dynamicFormat2,
                	   "readonly": viewFlag,
                	   "options": {
                		   "callback":{"changed" : "vm.criteria2Changed"}
                	   }
                   },
                   {
                	   "label": "label.feecode.criteriavalue",
                	   "model": "criteriaValue",
                	   "type": dynamicType3,
                	   "readonly": viewFlag,
                	   "format": dynamicFormat3,
                	   "options": {}
                   }
                ];
				if (ctrl.feeCode.tierType2 && ctrl.feeCode.tierType2 != 'N') {
					columnDefs = columnDefs2;
				}
				if(ctrl.validatorConfig) ctrl.layoutConfig.formConfigs.tierCriteria.tableConfigs.table.validatorConfig = ctrl.validatorConfig.tierCriterias;
				ctrl.layoutConfig.formConfigs.tierCriteria.tableConfigs.table.columnDefs = columnDefs;
				ctrl.tierCriteriaInnerGridOptions = gridService.createInnerGridOptions($scope, ctrl.layoutConfig.formConfigs.tierCriteria.tableConfigs.table, tierCriteriaRowSelectionChanged);
				ctrl.tierCriteriaInnerGridOptions.data = 'vm.feeCode.tierCriterias';
				ctrl.tierCriteriaInnerGridOptions.verifyData  = 'vm.feeCodeOld.tierCriterias';
				function tierCriteriaRowSelectionChanged(eventRow, selectedRows) {
					ctrl.selectedTierCriterias = selectedRows;
				}
			}	
		}
		
		function controlTierCalcType(ctrl) {
			if (ctrl.feeCode.tierType != 'N' && ctrl.feeCode.tierType == 'T') {
				ctrl.tierCalcTypeOptions = getTierCalcTypeOptions(true); 
			} else {
				ctrl.tierCalcTypeOptions = getTierCalcTypeOptions(false);
			}
		}
		
		function getTierCalcTypeOptions(ifStep) {
			var option1 = [ {
				"value" : "N",
				"label" : "label.feecode.tiercalctype.none"
			},{
				"value" : "I",
				"label" : "label.feecode.tiercalctype.interpolation"
			},{
				"value" : "S",
				"label" : "label.feecode.tiercalctype.step"
			},{
				"value" : "B",
				"label" : "label.feecode.tiercalctype.single"
			},{
				"value" : "C",
				"label" : "label.feecode.tiercalctype.combo"
			},{
				"value" : "A",
				"label" : "label.feecode.tiercalctype.static"
			}];
			var option2 = [  {
				"value" : "N",
				"label" : "label.feecode.tiercalctype.none"
			},{
				"value" : "I",
				"label" : "label.feecode.tiercalctype.interpolation"
			}];
			if(ifStep){
				return option1;
			}else {
				return option2;
			}
		}
		
		function validateTierCriteria ($scope, ctrl) {
			if (ctrl.feeCode.tierType != 'N' && !(ctrl.feeCode.tierCriterias && ctrl.feeCode.tierCriterias.length > 0)) {
				var msg = 'Tier Criteria is Required!';
				return msg;
			}
			if (ctrl.feeCode.tierType != 'N' && ctrl.feeCode.tierCriterias.length > 0) {
				// check empty 
				for (var i = 0; i < ctrl.feeCode.tierCriterias.length; i++) {
					var tierCriteria = ctrl.feeCode.tierCriterias[i];
					//
					if (ctrl.feeCode.tierType == 'E') {
						var dateVal = tierCriteria.criteria;
						if(arithService.gt(dateVal, 0) && !isDate(String(dateVal))){
							tierCriteria.criteria = '';
						}
					}
					if (ctrl.feeCode.tierType2 == 'E') {
						var dateVal = tierCriteria.criteria2;
						if(arithService.gt(dateVal, 0) && !isDate(String(dateVal))){
							tierCriteria.criteria2 = '';
						}
					}
					//tire required check
					if (!tierCriteria.criteria) {
						var msg = 'Valid Tier Criteria is Required!';
						return msg;
					} else if (!tierCriteria.criteriaValue) {
						var msg = 'Value is Required!';
						return msg;
					} else if (ctrl.feeCode.tierType2 != 'N' && !tierCriteria.criteria2) {
						var msg = 'Valid Tier2 Criteria is Required!';
						return msg;
					}
				}
				
				// check next must bigger latest
				// tier compare
				var lastCriteria;
				for (var i = 0; i < ctrl.feeCode.tierCriterias.length; i++) {
					var tierCriteria = ctrl.feeCode.tierCriterias[i];
					var criteria = tierCriteria.criteria;
					if (ctrl.feeCode.tierType == "D" || ctrl.feeCode.tierType == "T"){
						criteria = formatService.parseNumber(criteria);
					} else if(ctrl.feeCode.tierType == "U" || ctrl.feeCode.tierType == "A" ){
						criteria = formatService.parseMoney(criteria);
					} 
					if (i == 0) {
						lastCriteria = criteria;
						continue;
					}
					// current tierCriteria.criteria need same with lastCriteria, because hasFrontSameCriteria is 'Y'
					// must can be first 2, first line hasFrontSameCriteria must 'N'
					if (tierCriteria.hasFrontSameCriteria == 'Y') {
						continue;
					}
					//
					var comapreFail = false;
					if (ctrl.feeCode.tierType2 == 'N') {// no tire2
						if (arithService.lte(criteria, lastCriteria)) comapreFail = true;
					} else {// has tire2
						if (tierCriteria.hasFrontSameCriteria == 'N') {// new add tire1 line, don't allow equal whth front
							if (arithService.lte(criteria, lastCriteria)) comapreFail = true;
						}
					}
					if (comapreFail) {
						var msg = 'Criteria must be bigger than previous Criteria!';
						return msg;
					}
					lastCriteria = criteria;
				}
				
				// tier2 compare
				if (ctrl.feeCode.tierType2 != 'N') {// has tier and tier2
					var tier = {};
					for (var i = 0; i < ctrl.feeCode.tierCriterias.length; i++) {
						var tierCriteria = ctrl.feeCode.tierCriterias[i];
						var criteria = tierCriteria.criteria;
						if (ctrl.feeCode.tierType == "D" || ctrl.feeCode.tierType == "T"){
							criteria = formatService.parseNumber(criteria);
						} else if(ctrl.feeCode.tierType == "U" || ctrl.feeCode.tierType == "A" ){
							criteria = formatService.parseMoney(criteria);
						} 
						if (tier[criteria]) {
							tier[criteria].push(tierCriteria);
						} else {
							tier[criteria] = [];
							tier[criteria].push(tierCriteria);
						}
					}
					// check compare
					for(var a in tier) {
						// get tier2Criterias in same one tier
						var tier2CriteriasWhthOneTire = tier[a];
						
						var lastCriteria2;
						for (var i = 0; i < tier2CriteriasWhthOneTire.length; i++) {
							var tierCriteria = tier2CriteriasWhthOneTire[i];
							var criteria2 = tierCriteria.criteria2;
							if(ctrl.feeCode.tierType2 == "C" || ctrl.feeCode.tierType2 == "D" || ctrl.feeCode.tierType2 == "T"){
								criteria2 = formatService.parseNumber(criteria2);
							} else if(ctrl.feeCode.tierType2 == "U" || ctrl.feeCode.tierType2 == "A" ){
								criteria2 = formatService.parseMoney(criteria2);
							} 
							if (i == 0) {
								lastCriteria2 = criteria2;
								continue;
							}
							//
							if (arithService.lte(criteria2, lastCriteria2)) {
								var msg = 'Criteria2  must be bigger than previous Criteria2 in Same Criteria!';
								return msg;
							}
							lastCriteria2 = criteria2;
						}
					}
				}
			}
		}
		
		/**
		 * if the date is valid: 20090102, 2009-01-02, 2009/01/02
		 */
		function isDate(s){
			var r = s.match(/^(\d{1,4})(|-|\/)(\d{1,2})\2(\d{1,2})$/); 
			if(r==null)return false; 
			var d= new Date(r[1], r[3]-1, r[4]); 
			return (d.getFullYear()==r[1]&&(d.getMonth()+1)==r[3]&&d.getDate()==r[4]);
		}
		
		/**
		 * reset TierCriteria for hasSameCriteria
		 * if tierType2 isnot "N", then may be hidden hasSameCriteria
		 */
		function resetTierCriteria (ctrl) {
			// need hidden some first column criteria
			if (ctrl.feeCode.tierType != "N" && ctrl.feeCode.tierType2 != "N") {
				var lastCriteria;
				for (var i = 0; i < ctrl.feeCode.tierCriterias.length; i++) {
					var tierCriteria = ctrl.feeCode.tierCriterias[i];
					// need exclude, will be remove by framework
					if (tierCriteria.removeSelectedFlag) continue;
					var criteria = tierCriteria.criteria;
					if (ctrl.feeCode.tierType == "D" || ctrl.feeCode.tierType == "T"){
						criteria = formatService.parseNumber(criteria);
					} else if(ctrl.feeCode.tierType == "U" || ctrl.feeCode.tierType == "A" ){
						criteria = formatService.parseMoney(criteria);
					} 
					if (i == 0) {
						lastCriteria = criteria;
						tierCriteria.hasFrontSameCriteria = "N";
						continue;
					}
					//
					if (lastCriteria && arithService.eq(criteria, lastCriteria)) {
						tierCriteria.hasFrontSameCriteria = "Y";
					} else {
						tierCriteria.hasFrontSameCriteria = "N";
					}
					lastCriteria = criteria;
				}
			} 
			// also need open hidden first column
			else if (ctrl.feeCode.tierType != "N" && ctrl.feeCode.tierType2 == "N") {
				if (ctrl.feeCode.tierCriterias && ctrl.feeCode.tierCriterias.length) {
					for (var i = 0; i < ctrl.feeCode.tierCriterias.length; i++) {
						var tierCriteria = ctrl.feeCode.tierCriterias[i];
						tierCriteria.hasFrontSameCriteria = "N";
					}
				}
			}
		}
		
		function initListFilterData(ctrl) {
			var defer = $q.defer();
			ajaxService.getFeeCalcTypeOptions().then(function(response) {
				defer.resolve(response.data);
			}, angular.noop);
			return defer.promise;
		}
		
		return {
			initOptionData: initOptionData,
			initTierCriteria: initTierCriteria,
			initLayoutAndModel: initLayoutAndModel,
			validateTierCriteria: validateTierCriteria,
			initListFilterData : initListFilterData
		};
	}
})(angular);
